package com.liu.yupao.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liu.yupao.common.ErrorCode;
import com.liu.yupao.exception.BusinessException;
import com.liu.yupao.model.dto.team.TeamAddRequest;
import com.liu.yupao.model.dto.team.TeamQueryRequest;
import com.liu.yupao.model.dto.team.TeamUpdateRequest;
import com.liu.yupao.model.entity.Team;
import com.liu.yupao.model.entity.User;
import com.liu.yupao.model.entity.UserTeam;
import com.liu.yupao.model.enums.TeamStatusEnum;
import com.liu.yupao.model.vo.TeamUserVO;
import com.liu.yupao.model.vo.UserVO;
import com.liu.yupao.service.TeamService;
import com.liu.yupao.mapper.TeamMapper;
import com.liu.yupao.service.UserService;
import com.liu.yupao.service.UserTeamService;
import com.liu.yupao.utils.CopyUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.querydsl.QuerydslUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.context.Theme;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Year;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import static com.liu.yupao.model.enums.TeamStatusEnum.*;

/**
* @author Administrator
* @description 针对表【team(队伍表)】的数据库操作Service实现
* @createDate 2025-10-10 22:04:14
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService{

    @Resource
    private UserService userService;

    @Resource
    private UserTeamService userTeamService;


    /**
     * 新增队伍信息
     * @param teamAddRequest 队伍新增请求类
     * @return 队伍id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)  //事务注解
    public long addTeam(TeamAddRequest teamAddRequest, HttpServletRequest request) {
        //1.校验请求类是否为空
        if (teamAddRequest==null){
            throw new BusinessException (ErrorCode.PARAMS_ERROR);
        }
        //2.判断用户是否登录
        User loginUser = userService.getLoginUser (request);
        //3.校验请求参数
        String name = teamAddRequest.getName ();
        Integer maxNum = teamAddRequest.getMaxNum ();
        String description = teamAddRequest.getDescription ();
        String expireTime = teamAddRequest.getExpireTime ();
//        //字符串转日期
        DateTime exTime = DateUtil.parse (expireTime);
        Integer status = teamAddRequest.getStatus ();
        String password = teamAddRequest.getPassword ();
        //3.1.名称<20
        if (StringUtils.isEmpty (name) || name.length ()>20){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"队伍名称过长!");
        }
        //3.2.描述<50
        if (StringUtils.isNotEmpty (description) && description.length ()>50){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"队伍描述信息过长!");
        }
        //3.3.maxNum<20
        if (maxNum<1 || maxNum>20){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"队伍人数不满足要求!");
        }
        //3.4.status是否公开
        TeamStatusEnum statusEnum = TeamStatusEnum.getByValue (status);
        if (statusEnum==null){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"创建队伍信息有误!");
        }

        //3.5.如果status是加密状态，一定设置密码，且密码<=32
        if (SECRET.getValue ().equals (status)){
            if (StringUtils.isEmpty (password) || password.length ()>32){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"密码设置过长!");
            }
        }
        //3.6.超时时间>当前时间  A.after(B) A在B之后
        if (exTime!=null){
            if (new Date ().after (exTime)){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"过期时间需要大于当期时间!");
            }
        }
        //3.7.校验用户最多创建5个队伍
        //todo 可能会有bug 可能同时创建很多队伍 加锁解决
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<> ();
        teamQueryWrapper.eq ("userId",loginUser.getId ());
        List<Team> teams = this.list (teamQueryWrapper);
        if (teams.size ()>=5){
            throw new BusinessException (ErrorCode.NO_AUTH,"普通用户最多建立5个队伍!");
        }
        //4.插入队伍信息到队伍表
        Team team = CopyUtils.copy (teamAddRequest, Team.class);
        team.setExpireTime (exTime);
        team.setUserId (loginUser.getId ());
        boolean result = this.save (team);
        Long teamId = team.getId ();
        if (!result){
            throw new BusinessException (ErrorCode.SYSTEM_ERROR,"数据库插入失败!");
        }
        //5.插入用户=> 队伍关系到关系表
        UserTeam userTeam = new UserTeam ();
        userTeam.setUserId (loginUser.getId ());
        userTeam.setTeamId (teamId);
        userTeam.setJoinTime (new Date ());
        result = userTeamService.save (userTeam);
        if (!result){
            throw new BusinessException (ErrorCode.SYSTEM_ERROR,"数据库插入失败!");
        }
        return teamId;
    }

    /**
     * 删除队伍
     * @param teamId 队伍id
     * @return 0 1
     */
    @Override
    public boolean deleteTeam(Long teamId) {
        if (teamId==null || teamId<=0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR);
        }
        //判断队伍信息是否存在
        Team oddTeam = this.getById (teamId);
        if (oddTeam==null){
            throw new BusinessException (ErrorCode.NULL_ERROR);
        }
        //删除队伍
        return this.removeById (teamId);
    }

    /**
     * 查询队伍信息
     * @param teamQueryRequest 查询信息
     * @return 队伍列表
     */
    @Override
    public List<TeamUserVO> queryTeams(TeamQueryRequest teamQueryRequest,HttpServletRequest request,Boolean isInclude) {
        //1.从请求中获取队伍名称，如果存在则作为查询条件
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<> ();
        List<TeamUserVO> teamUserVOS = new LinkedList<> ();
        List<Long> idList = teamQueryRequest.getIdList ();
        if (isInclude){
            if (CollUtil.isEmpty (idList)){
                return teamUserVOS;
            }
        }
        //校验参数
        Long id = teamQueryRequest.getId ();
        Long userId = teamQueryRequest.getUserId ();
        String name = teamQueryRequest.getName ();
        String description = teamQueryRequest.getDescription ();
        Integer status = teamQueryRequest.getStatus ();
        if (CollUtil.isNotEmpty (idList)){
            teamQueryWrapper.in ("id",idList);
        }
        if (id!=null && id > 0) teamQueryWrapper.eq ("id", id);
        if (userId!=null && userId > 0) teamQueryWrapper.eq ("userId", userId);
        if (StringUtils.isNotEmpty (name)) teamQueryWrapper.like ("name", name);
        if (StringUtils.isNotEmpty (description)) teamQueryWrapper.like ("description", description);
        //4.通过搜索关键字对名称还有描述同时搜索
        String searchText = teamQueryRequest.getSearchText ();
        if (StringUtils.isNotEmpty (searchText)){
            teamQueryWrapper.and (qw->qw.like ("name",searchText).or ().like ("description",searchText));
        }
        //根据状态来查询
        TeamStatusEnum statusEnum = TeamStatusEnum.getByValue (status);
        if (statusEnum==null){
           statusEnum=TeamStatusEnum.PUBLIC;
        }
        //5.只有管理员才可以进行查看加密和私有的房间
        if (!userService.isAdmin (request) && !TeamStatusEnum.PUBLIC.equals (statusEnum)){
            throw new BusinessException (ErrorCode.NO_AUTH);
        }
        teamQueryWrapper.eq ("status",statusEnum.getValue ());

        //2.不展示已经过期的队伍(expireTime == null or expireTime >now)
        /**
         * and expireTime>new Date() or expireTime is NULL
         */
        teamQueryWrapper.and (qw->qw.gt ("expireTime",new Date ()).or ().isNull ("expireTime"));

        //3.关联查询已经加入的用户信息(创建人信息)
        List<Team> teams = this.list (teamQueryWrapper);

        if (CollUtil.isEmpty (teams)){{
            return teamUserVOS;
        }}
        for (Team team : teams) {
            Long userId1 = team.getUserId ();
            if (userId1 == null) {
                continue;
            }
            User user = userService.getById (userId1);
            TeamUserVO teamUserVO = CopyUtils.copy (team, TeamUserVO.class);
            teamUserVO.setCreateUser (UserVO.toUserVO (user));
            //收集
            teamUserVOS.add (teamUserVO);
        }
        return teamUserVOS;
    }

    /**
     * 更新队伍信息
     * @param teamUpdateRequest 队伍更新请求类
     * @return true false
     */
    @Override
    public boolean updateUser(TeamUpdateRequest teamUpdateRequest,HttpServletRequest request) {

        //1.判断请求参数是否为空
        Long id = teamUpdateRequest.getId ();
        if (id==null || id <=0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR);
        }
        //2.判断队伍是否存在
        Team oldTeam = this.getById (id);
        if (oldTeam==null){
            throw new BusinessException (ErrorCode.NULL_ERROR,"队伍不存在!");
        }
        //校验参数
        String name = teamUpdateRequest.getName ();
        Integer maxNum = teamUpdateRequest.getMaxNum ();
        String description = teamUpdateRequest.getDescription ();
        String password = teamUpdateRequest.getPassword ();
        checkValid (name,password,maxNum,description);

        //3.只有自己或者是管理员可以修改
        User loginUser = userService.getLoginUser (request);
        if (!userService.isAdmin (request) && !oldTeam.getUserId ().equals (loginUser.getId ())){
            throw new BusinessException (ErrorCode.NO_AUTH);
        }
        //4.如果队伍状态不是加密状态，修改密码则提示错误
        Integer status = teamUpdateRequest.getStatus ();
        Integer oldTeamStatus = oldTeam.getStatus ();
        TeamStatusEnum oldStatusEnum = TeamStatusEnum.getByValue (oldTeamStatus);
        if (status==null){
            if (PUBLIC.equals (oldStatusEnum) && StringUtils.isNotEmpty (password)){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"公共队伍不允许添加密码!");
            }
        }
        //如果队伍改为加密队伍，必须有要设置密码
        oldStatusEnum=TeamStatusEnum.getByValue (status);
        if (SECRET.equals (oldStatusEnum) && StringUtils.isEmpty (password)){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"加密队伍必须设置密码!");
        }
        //5.更新到数据库
        Team team = CopyUtils.copy (teamUpdateRequest, Team.class);
        boolean result = this.updateById (team);
        if (!result){
            throw new BusinessException (ErrorCode.SYSTEM_ERROR,"数据库操作失败!");
        }
        return true;
    }

    /**
     * 用户加入队伍
     * @param teamId 队伍id
     * @return 加入队伍信息id
     */
    @Override
    public boolean joinTeam(Long teamId,String password,HttpServletRequest request) {
        //获取当前登录用户信息
        User loginUser = userService.getLoginUser (request);
        //1.校验参数
        if (teamId==null || teamId<=0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById (teamId);
        //5.禁止加入私有的队伍（todo：把不涉及到数据库查询的放到前面，节省内存消耗）
        TeamStatusEnum statusEnum = getByValue (team.getStatus ());
        if (PRIVATE.equals (statusEnum)){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"禁止加入私人队伍!");
        }
        //6.如果队伍是加密的，密码必须匹配
        String teamPassword = team.getPassword ();
        if (SECRET.equals (statusEnum)){
            if (!teamPassword.equals (password)){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"加入队伍密码错误!");
            }
        }
        //未过期
        Date expireTime = team.getExpireTime ();
        if (expireTime!=null){
            if (new Date ().after (expireTime) ){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"该队伍已经过期,请选择加入其他队伍!");
            }
        }
        //2.判断加入队伍是否存在，只能加入未满、未过期的队伍
        if (team==null){
            throw new BusinessException (ErrorCode.NULL_ERROR,"加入队伍不存在!");
        }
        //查询队伍人数 判断是否超出
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<> ();
        userTeamQueryWrapper.eq ("teamId",team.getId ());
        List<UserTeam> userTeamList = userTeamService.list (userTeamQueryWrapper);
        //队伍人数
        if (userTeamList.size ()>=team.getMaxNum ()){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"该队伍人数已满,请选择加入其他队伍!");
        }
        //3.用户最多加入5个队伍
        userTeamQueryWrapper=new QueryWrapper<> ();
        userTeamQueryWrapper.eq ("userId",loginUser.getId ());
        List<UserTeam> list = userTeamService.list (userTeamQueryWrapper);
        if (list.size ()>=5){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"最多加入五个队伍!");
        }
        //4.不能重复加入已加入的队伍（幂等性）
        // 也可以查询用户-队伍表中是否存在一天信息  userTeamQueryWrapper.eq ("userId",loginUser.getId ()).eq("teamId",team.getId ())
        for (UserTeam userTeam : list) {
            if (userTeam.getTeamId ().equals (teamId)){
                throw new BusinessException (ErrorCode.PARAMS_ERROR,"您已经加入该队伍!");
            }
        }
        //7.新增队伍，用户关联信息
        UserTeam userTeam = new UserTeam ();
        userTeam.setUserId (loginUser.getId ());
        userTeam.setTeamId (teamId);
        userTeam.setJoinTime (new Date ());
        boolean result = userTeamService.save (userTeam);
        if (!result){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"插入数据库失败!");
        }
        return true;
    }

    /**
     * 用户退出队伍
     * @param teamId 队伍id
     * @param request 请求用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean exitTeam(Long teamId, HttpServletRequest request) {
        //获取登录用户
        User loginUser = userService.getLoginUser (request);
        //1.校验请求参数
        if (teamId==null || teamId<=0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"参数错误!");
        }
        //2.如果队伍
        //2.1.只剩一人，就解散队伍
        //判断队伍是否存在
        Team oldTeam = this.getById (teamId);
        if (oldTeam==null){
            throw new BusinessException (ErrorCode.NULL_ERROR,"该队伍不存在!");
        }
        //判断用户是否在这个队伍中
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<> ();
        userTeamQueryWrapper.eq ("userId",loginUser.getId ());
        userTeamQueryWrapper.eq ("teamId",teamId);
        UserTeam userTeam = userTeamService.getOne (userTeamQueryWrapper);
        if (userTeam==null){
            throw new BusinessException (ErrorCode.NULL_ERROR,"您不在此队伍中!");
        }
        userTeamQueryWrapper=new QueryWrapper<> ();
        userTeamQueryWrapper.eq ("teamId",teamId);
        List<UserTeam> list = userTeamService.list (userTeamQueryWrapper);
        if (list.size ()==1 && list.get (0).getUserId ().equals (loginUser.getId ())){
            //解散队伍
            this.removeById (teamId);
        }else {
            //2.2还有其他人
            //2.2.1.如果是队长退出队伍，队长转移给第二时间加入队伍的人
            if (oldTeam.getUserId ().equals (loginUser.getId ())){
                //转让队长给第二加入的人,这里只需要查询一部分数据即可 全查出来浪费性能
                userTeamQueryWrapper=new QueryWrapper<> ();
                userTeamQueryWrapper.eq ("teamId",teamId);
                //自定义sql查询 只查询少量数据即可 提高查询性能
                userTeamQueryWrapper.last ("order by id limit 2");
                list=userTeamService.list (userTeamQueryWrapper);
                if (CollUtil.isEmpty (list) || list.size ()<=1){
                    throw new BusinessException (ErrorCode.SYSTEM_ERROR);
                }
                oldTeam.setUserId (list.get (1).getUserId ());
                boolean b = this.updateById (oldTeam);
                if (!b){
                    throw new BusinessException (ErrorCode.SYSTEM_ERROR,"数据库更新失败!");
                }
            }
        }
        //2.2.2不是队长 直接删除
        //删除队伍-用户信息
       return userTeamService.removeById (userTeam.getId ());
    }

    /**
     * 队长解散队伍
     * @param teamId 队伍id
     * @param request 请求信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class) //事务注解
    public boolean releaseTeam(Long teamId, HttpServletRequest request) {
        User loginUser = userService.getLoginUser (request);
        //1.校验请求参数
        if (teamId==null || teamId<=0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR);
        }
        //2.判断队伍是否存在
        Team team = this.getById (teamId);
        if (team==null){
            throw new BusinessException (ErrorCode.NULL_ERROR,"该队伍不存在!");
        }
        //3.判断你是不是队长
        if (!team.getUserId ().equals (loginUser.getId ())){
            throw new BusinessException (ErrorCode.NO_AUTH,"您不是队长!");
        }
        //4.解除队伍关联信息
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<> ();
        userTeamQueryWrapper.eq ("teamId",teamId);
        boolean result= userTeamService.remove (userTeamQueryWrapper);
        if (!result){
            throw new BusinessException (ErrorCode.SYSTEM_ERROR,"操作数据失败!");
        }
        //5.删除队伍信息
        result = this.removeById (teamId);
        if (!result){
            throw new BusinessException  (ErrorCode.SYSTEM_ERROR,"操作数据失败!");
        }
        return true;
    }

    /**
     * 公共校验参数方法
     */
    private void checkValid(String name,String password,Integer maxNum,String description){
        if (StringUtils.isNotEmpty (name) && name.length ()>10){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"队伍名称过长!");
        }
        if (StringUtils.isNotEmpty (password) && password.length ()>10){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"密码过长!");
        }
        if (ObjectUtils.isNotEmpty (maxNum) && maxNum>30){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"队伍人数限制30人!");
        }
        if (StringUtils.isNotEmpty (description) && description.length ()>=50){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"描述字数小于50字");
        }
    }
}




